package com.sky.aop;

import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.entity.Category;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.time.LocalDateTime;

// 定义切面：切面类注解，
// 通知方法，
// 通知类型（切入点表达式):使用前置通知，需要在方法执行前，对实体字段进行填充
// 切入点表达式:使用注解方式
@Component
@Aspect
@Slf4j
public class AutoFillAspect {
    @Before("@annotation(com.sky.aop.AutoFill)")
    public void autoFill(JoinPoint joinPoint){
       // 获取到执行的方法，通过joinPoint来获取正在运行的方法
        Signature signature = joinPoint.getSignature();

        String methodName = signature.getName();
        log.info("[自动填充切面...] 方法:{}",methodName);
        // 填充字段的思路：获取到方法的参数-实体类，给实体类的属性赋值
        // 如果是插入，对4个字段赋值：创建、更新时间；创建、更新者ID
        // 如果是更新，对2个字段赋值，更新时间，更新者ID
        // 获取到当前的方法，通过反射获取到注解及注解的属性
        try {
            // joinPoint.getTarget().getClass() 通过连接点，获取当前运行的对象，通过对象获取字节码（Class）
            // 获取了字节码，就可以获取到类中的字段、方法，构造方法
            // 正在运行的方法
            MethodSignature methodSignature = (MethodSignature)signature;
            Method method = methodSignature.getMethod();
            AutoFill annotation = method.getAnnotation(AutoFill.class);
            OperationType value = annotation.value();
            if (value == OperationType.INSERT){
                log.info("[自动填充切面...] 当前是插入");
                // 通过反射，对参数（实体类）的字段进行填充
                // 思路：获取方法的参数,参数就是实体类，然后通过实体类的setXXX方法进行赋值
                Object[] args = joinPoint.getArgs();
                Object entityObj = args[0];
                log.info("[自动填充切面...] 当前是插入:entityObj:{}",entityObj);
                //  category对象，修改这个对象的属性，这几个实体类，都有4个公共属性
                // 通过反射，对实体类对象的属性进行赋值，使用setter方法进行赋值
                // 此时，获取的方法的无参数 setCreateTime() setCreateTime(LocalDateTime)
                Method setCreateTime = entityObj.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME,LocalDateTime.class);
                Method setUpdateTime = entityObj.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME,LocalDateTime.class);
                // setCreateUser(Long.class)
                Method setCreateUser = entityObj.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER,Long.class);
                Method setUpdateUser = entityObj.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER,Long.class);
                // 方法调用
                setCreateTime.invoke(entityObj, LocalDateTime.now());
                setUpdateTime.invoke(entityObj, LocalDateTime.now());
                // 用户ID，从ThreadLocal中获取
                setCreateUser.invoke(entityObj, BaseContext.getCurrentId());
                setUpdateUser.invoke(entityObj, BaseContext.getCurrentId());

            }else{
                Object[] args = joinPoint.getArgs();
                Object entityObj = args[0];
                log.info("[自动填充切面...] 当前是更新:entityObj:{}",entityObj);
                //  category对象，修改这个对象的属性，这几个实体类，都有4个公共属性
                // 通过反射，对实体类对象的属性进行赋值，使用setter方法进行赋值
                // 此时，获取的方法的无参数 setUpdateTime(LocalDateTime)
                 Method setUpdateTime = entityObj.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME,LocalDateTime.class);
                // setUpdateUser(Long.class)
                 Method setUpdateUser = entityObj.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER,Long.class);
                // 方法调用
                 setUpdateTime.invoke(entityObj, LocalDateTime.now());
                // 用户ID，从ThreadLocal中获取
                 setUpdateUser.invoke(entityObj, BaseContext.getCurrentId());

            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}


















